#pragma once

#include "../Libraries/Singleton/Singleton.h"
#include "Handles.h"
#include "AudioTypes.h"
#include <Windows.h>
#include <list>
#include <map>

#undef PlaySound

namespace sndcore
{
	class LowLevelCore;
	class Channel;
}

namespace Audio
{
	class CoreSystem : public Singleton<CoreSystem>
	///////////////////////////////////////////////////////////////////////////////
	// Description: All data is stored in here so every file that includes the
	//				SoundSystem doesn't have to recompile every time something
	//				in this header changes
	//
	// Recent Changes:
	// -brasmuss 3/29/2007 : Created
	///////////////////////////////////////////////////////////////////////////////
	{
		friend class Singleton<CoreSystem>;

	public:
	//////////////////////////
	// HIGH LEVEL INTERFACE
	//////////////////////////
		bool Initialize(HWND hwnd, bool for_tool);
		bool Update(float delta);
		bool TriggerEvent(const char* name, const XMLFileHandle xmlFile);
		bool StopEvents();

	/////////////////////
	// DIRECT ACCESS
	/////////////////////
		FileHandle		LoadSoundFile(		const WCHAR* file );													//!< Load a sound file into memory and return the sound's handle
		FileHandle      LoadStreamFile(		const WCHAR* file );													//!< Stream a sound file and return the sound's handle
		ChannelHandle	PlayFile(			const WCHAR* file, bool looping = false, float volume = 1.f );			//!< Directly streams and plays a sound by filename
		ChannelHandle	PlayFile(			const FileHandle& fileID, bool looping = false, float volume = 1.f );	//!< Plays a file loaded by sound file
		void			UnloadSoundFile(	const FileHandle& fileID );												//!< Unloads a loaded sound file by sound handle

		bool 			IsPlaying(			const ChannelHandle& soundID );											//!< Returns true if a sound is currently playing
		void 			PlaySound(			const ChannelHandle& soundID );											//!< Plays a single sound by sound handle.
		void 			SetVolume(			const ChannelHandle& soundID, float volume);							//!< Sets the volume of a sound by sound handle.
		void 			StopSound(			const ChannelHandle& soundID );											//!< Stops a specified sound by sound handle.

		sndcore::Channel* GetChannel(		const ChannelHandle& soundID );

	/////////////////////////
	// TOOL INTERFACE
	/////////////////////////
		// XML LOADING/SAVING
		XMLFileHandle	LoadSoundXML(		const char* file );
		bool			UnloadSoundXML(		XMLFileHandle handle );
		bool			SaveSoundXML(		XMLFileHandle handle,	const char* saveAs );
		XMLFileHandle	LoadBlankXML(		const char* name );							//!< For tool use
		XMLFileHandle	GetXMLHandle(		const char* file );
		void			Clear();

		// Sound file management
		FileHandle		GetSoundFileHandle(	bool first, XMLFileHandle xmlFile );
		FileHandle		NewSoundFile(		const char* name,				const char* file,				XMLFileHandle xmlFile );
		const char*		GetSoundFilename(	const FileHandle& handle,										XMLFileHandle xmlFile );
		const char*		GetSoundName(		const FileHandle& handle,										XMLFileHandle xmlFile );
		bool			SetSoundFilename(	const FileHandle& handle,		const char* filename,			XMLFileHandle xmlFile );
		bool			SetSoundName(		const FileHandle& handle,		const char* name,				XMLFileHandle xmlFile );
		bool			RemoveSound(		const FileHandle& handle,		XMLFileHandle xmlFile );
		unsigned		GetSoundFreq(		const FileHandle& handle );
		unsigned		GetSoundBitDepth(	const FileHandle& handle );
		unsigned		GetSoundChannels(	const FileHandle& handle );
		int				GetSoundLength(		const FileHandle& handle );
	

		// Variable management
		VariableHandle	NewVariable(		const char* varName,			float min,		float max,		XMLFileHandle xmlFile );
		VariableHandle	GetVariableHandle(	bool first,														XMLFileHandle xmlFile );
		VariableHandle	GetVariableHandle(	const char* name,												XMLFileHandle xmlFile );
		const char*		GetVariableName(	const VariableHandle& handle,									XMLFileHandle xmlFile );
		float			GetVariableMin(		const VariableHandle& handle,									XMLFileHandle xmlFile );
		float			GetVariableMax(		const VariableHandle& handle,									XMLFileHandle xmlFile );
		float			GetVariableInitial(	const VariableHandle& handle,									XMLFileHandle xmlFile );
		float         	GetVariableValue(	const VariableHandle& handle,									XMLFileHandle xmlFile );
		bool			RemoveVariable(		const VariableHandle& handle,									XMLFileHandle xmlFile );
		bool			SetVariableName(	const VariableHandle& handle,	const char* name,				XMLFileHandle xmlFile );
		bool			SetVariableMin(		const VariableHandle& handle,	float min,						XMLFileHandle xmlFile );
		bool			SetVariableMax(		const VariableHandle& handle,	float max,						XMLFileHandle xmlFile );
		bool			SetVariableInitial(	const VariableHandle& handle,	float initial,					XMLFileHandle xmlFile );
		bool			SetVariableValue(	const VariableHandle& handle,	float value,					XMLFileHandle xmlFile );
		

		// Graph management
		GraphHandle		NewGraph(			const char* graphName,											XMLFileHandle xmlFile );
		GraphHandle		GetGraphHandle(		const char* name,												XMLFileHandle xmlFile );
		GraphHandle		GetGraphHandle(		bool  first,													XMLFileHandle xmlFile );
		bool			ClearGraph(			const GraphHandle& graphID,										XMLFileHandle xmlFile );
		bool			RemoveGraph(		const GraphHandle& graphID,										XMLFileHandle xmlFile );
		const char*		GetGraphName(		const GraphHandle& graphID,										XMLFileHandle xmlFile );
		bool			SetGraphName(		const GraphHandle& graphID,		const char* name,				XMLFileHandle xmlFile );
		bool			AddPoint(			const GraphHandle& graphID,		float x,	float y,			XMLFileHandle xmlFile );
		float         	GetGraphOutput(		const GraphHandle& graphID,		float input,					XMLFileHandle xmlFile );
		unsigned		GetPointCount(		const GraphHandle& graphID,										XMLFileHandle xmlFile );
		float			GetPointX(			const GraphHandle& graphID,		unsigned index,					XMLFileHandle xmlFile );
		float			GetPointY(			const GraphHandle& graphID,		unsigned index,					XMLFileHandle xmlFile );

		// Events, SubEvents & Effects
		EventHandle		NewEvent(			const char* name,				bool looping,					XMLFileHandle xmlFile );
		EventHandle		GetEventHandle(		bool  first,					XMLFileHandle xmlFile );
		bool			RemoveEvent(		const EventHandle& eventID,																	XMLFileHandle xmlFile );
		SubEventHandle	AddSubEvent(		const EventHandle& eventID,		const char* soundName,	float triggerTime,	int pitchShift, bool streaming,				 XMLFileHandle xmlFile );
		bool			RemoveSubEvent(		const EventHandle& eventID,		const SubEventHandle& subID,								XMLFileHandle xmlFile );
		EffectHandle	AddSoundEffect(		const EventHandle& eventID,		const SubEventHandle& subID,	const char* graphName,		const char* varName,		 unsigned effect, XMLFileHandle xmlFile );
		EffectHandle	AddSoundEffect(		const EventHandle& eventID,		const SubEventHandle& subID,	const GraphHandle& graphID, const VariableHandle& varID, unsigned effect, XMLFileHandle xmlFile );
		bool			RemoveSoundEffect(	const EventHandle& eventID,		const SubEventHandle& subID,	const EffectHandle& effect,	XMLFileHandle xmlFile );
		const char*		GetEventName(		const EventHandle& eventID,		XMLFileHandle xmlFile );
		bool			GetEventLooping(	const EventHandle& eventID,		XMLFileHandle xmlFile );
		SubEventHandle	GetSubEventHandle(	const EventHandle& eventID,		bool  first,					XMLFileHandle xmlFile );
		const char*		GetSoundName(		const EventHandle& eventID,		const SubEventHandle& subID,	XMLFileHandle xmlFile );
		float			GetTriggerTime(		const EventHandle& eventID,		const SubEventHandle& subID,	XMLFileHandle xmlFile );
		int				GetPitchShift(		const EventHandle& eventID,		const SubEventHandle& subID,	XMLFileHandle xmlFile );
		bool			GetStreaming(		const EventHandle& eventID,		const SubEventHandle& subID,	XMLFileHandle xmlFile );
		EffectHandle	GetEffectHandle(	const EventHandle& eventID,		const SubEventHandle& subID,	bool  first,				XMLFileHandle xmlFile );
		GraphHandle		GetEffectGraph(		const EventHandle& eventID,		const SubEventHandle& subID,	const EffectHandle& fxID,	XMLFileHandle xmlFile );
		VariableHandle	GetEffectVariable(	const EventHandle& eventID,		const SubEventHandle& subID,	const EffectHandle& fxID,	XMLFileHandle xmlFile );
		unsigned		GetEffectType(		const EventHandle& eventID,		const SubEventHandle& subID,	const EffectHandle& fxID,	XMLFileHandle xmlFile );

		// Sound path management
		bool 			SetSoundPath(		const char* path,				XMLFileHandle xmlFile );
		const char*		GetSoundPath(		XMLFileHandle xmlFile );

	protected:
		CoreSystem();
		~CoreSystem();

	private: // PRIVATE METHODS
		XMLFileHandle	UniqueXMLFileHandle() { return m_uniqueXMLFileHandle++; }
		XMLAudioData*	GetXMLAudioData( XMLFileHandle handle );
		Variable*		getVariableData(XMLFileHandle xmlFile,	const VariableHandle& varID);
		Graph*			getGraphData(XMLFileHandle xmlFile,		const GraphHandle& graphID);
		EventData*		getEventData(XMLFileHandle xmlFile,		const EventHandle& eventID);
		SubEventData*	getSubEventData(XMLFileHandle xmlFile,	const EventHandle& eventID,		const SubEventHandle& subID );
		EffectData*		getEffectData(XMLFileHandle xmlFile,	const EventHandle& eventID,		const SubEventHandle& subID, const EffectHandle& fxID );

	private: // PRIVATE DATA
		sndcore::LowLevelCore*	m_lowLevel;
		xmldatamap_t			m_xmlData;				//!< Open XML files, similar to categories
		handlemap_t				m_xmlHandles;
		XMLFileHandle			m_uniqueXMLFileHandle;
		eventlist_t				m_activeEvents;			//!< A list of active events
	};
};
